# -*- coding: utf-8 -*-
"""
文本处理工具
提供文本相似度计算、字符串处理等功能
"""
import logging
import re
from collections import Counter

# 配置日志
logger = logging.getLogger("text_utils")


def calculate_jaccard_similarity(text1, text2):
    """计算Jaccard相似度
    
    Jaccard相似度 = 交集大小 / 并集大小
    
    Args:
        text1: 第一个文本
        text2: 第二个文本
        
    Returns:
        Jaccard相似度得分（0-1之间的浮点数）
    """
    if not text1 and not text2:
        return 1.0  # 两个空字符串被视为完全相似
    if not text1 or not text2:
        return 0.0  # 一个为空，一个不为空，视为完全不相似
    
    # 分词（使用字符级别）
    set1 = set(text1)
    set2 = set(text2)
    
    # 计算交集和并集
    intersection = len(set1 & set2)
    union = len(set1 | set2)
    
    # 避免除以零
    if union == 0:
        return 0.0
    
    return intersection / union


def calculate_levenshtein_similarity(text1, text2):
    """计算Levenshtein相似度
    
    Levenshtein相似度 = 1 - (编辑距离 / 最长字符串长度)
    
    Args:
        text1: 第一个文本
        text2: 第二个文本
        
    Returns:
        Levenshtein相似度得分（0-1之间的浮点数）
    """
    if not text1 and not text2:
        return 1.0  # 两个空字符串被视为完全相似
    if not text1 or not text2:
        return 0.0  # 一个为空，一个不为空，视为完全不相似
    
    # 计算编辑距离
    distance = _levenshtein_distance(text1, text2)
    
    # 计算相似度（归一化到0-1范围）
    max_length = max(len(text1), len(text2))
    similarity = 1 - (distance / max_length)
    
    return similarity


def _levenshtein_distance(s1, s2):
    """计算两个字符串之间的Levenshtein编辑距离
    
    Args:
        s1: 第一个字符串
        s2: 第二个字符串
        
    Returns:
        编辑距离（整数）
    """
    # 创建距离矩阵
    m, n = len(s1), len(s2)
    # 初始化矩阵（m+1行，n+1列）
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    
    # 初始化第一行和第一列
    for i in range(m + 1):
        dp[i][0] = i
    for j in range(n + 1):
        dp[0][j] = j
    
    # 填充矩阵
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            # 如果字符相同，不需要操作
            if s1[i-1] == s2[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                # 取插入、删除、替换操作中的最小值
                dp[i][j] = 1 + min(
                    dp[i-1][j],    # 删除
                    dp[i][j-1],    # 插入
                    dp[i-1][j-1]   # 替换
                )
    
    return dp[m][n]


def clean_text(text):
    """清理文本，去除特殊字符和多余空格
    
    Args:
        text: 待清理的文本
        
    Returns:
        清理后的文本
    """
    if not text:
        return ""
    
    # 转换为字符串
    text = str(text)
    
    # 去除多余空格
    text = re.sub(r'\s+', ' ', text)
    
    # 去除前后空格
    text = text.strip()
    
    return text


def standardize_text(text):
    """标准化文本，包括清理文本、转换为小写等
    
    Args:
        text: 待标准化的文本
        
    Returns:
        标准化后的文本
    """
    if not text:
        return ""
    
    # 清理文本
    text = clean_text(text)
    
    # 转换为小写
    text = text.lower()
    
    return text


def extract_numeric_parts(text):
    """从文本中提取数字部分
    
    Args:
        text: 包含数字的文本
        
    Returns:
        提取的数字列表
    """
    if not text:
        return []
    
    # 提取所有数字
    numbers = re.findall(r'\d+', str(text))
    
    # 转换为整数
    return [int(num) for num in numbers]


def calculate_cosine_similarity(text1, text2):
    """计算余弦相似度
    
    Args:
        text1: 第一个文本
        text2: 第二个文本
        
    Returns:
        余弦相似度得分（0-1之间的浮点数）
    """
    if not text1 and not text2:
        return 1.0  # 两个空字符串被视为完全相似
    if not text1 or not text2:
        return 0.0  # 一个为空，一个不为空，视为完全不相似
    
    # 分词并计算词频
    counter1 = Counter(text1)
    counter2 = Counter(text2)
    
    # 获取所有唯一字符
    all_chars = set(counter1.keys()).union(set(counter2.keys()))
    
    # 计算点积
    dot_product = sum(counter1.get(char, 0) * counter2.get(char, 0) for char in all_chars)
    
    # 计算向量长度
    magnitude1 = sum(value**2 for value in counter1.values()) ** 0.5
    magnitude2 = sum(value**2 for value in counter2.values()) ** 0.5
    
    # 避免除以零
    if magnitude1 == 0 or magnitude2 == 0:
        return 0.0
    
    return dot_product / (magnitude1 * magnitude2)


def calculate_weighted_similarity(text1, text2, weights=None):
    """计算加权综合相似度
    
    Args:
        text1: 第一个文本
        text2: 第二个文本
        weights: 各相似度指标的权重字典
        
    Returns:
        加权综合相似度得分（0-1之间的浮点数）
    """
    # 默认权重
    default_weights = {
        'jaccard': 0.4,
        'levenshtein': 0.4,
        'cosine': 0.2
    }
    
    # 使用传入的权重或默认权重
    if weights is None:
        weights = default_weights
    
    # 计算各相似度指标
    jaccard_sim = calculate_jaccard_similarity(text1, text2)
    levenshtein_sim = calculate_levenshtein_similarity(text1, text2)
    cosine_sim = calculate_cosine_similarity(text1, text2)
    
    # 计算加权综合相似度
    weighted_sim = (
        weights.get('jaccard', 0) * jaccard_sim +
        weights.get('levenshtein', 0) * levenshtein_sim +
        weights.get('cosine', 0) * cosine_sim
    )
    
    # 确保结果在0-1范围内
    weighted_sim = max(0, min(1, weighted_sim))
    
    return weighted_sim